﻿using System;

namespace Bettzueche.RLLibrary.Types {
    /// <summary>
    /// Ein <see cref="System.Tupel{T1,T2}"/> für Zustands-Aktionspaare
    /// </summary>
    public class SATupel : Tuple<IState,IAction> {

        public SATupel(IState state, IAction action) : base(state,action){
        }
    }

    /// <summary>
    /// Tupel aus Zustand (Item1) und Aktion (Item2).
    /// Zwei Tupel sind gleich, wenn ihre items gleich sind.
    /// </summary>
    public class SATupel<S,A> : Tuple<S, A>
        where S : IState
        where A : IAction
    {

        /// <summary>
        /// Gets the state. Äquivalent zu <c>Item1</c>.
        /// </summary>
        /// <value>
        /// The state.
        /// </value>
        public S State {
            get { return base.Item1; }
        }

        /// <summary>
        /// Gets the action. Äquivalent zu <c>Item2</c>
        /// </summary>
        /// <value>
        /// The action.
        /// </value>
        public A Action {
            get { return base.Item2; }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SATupel{S, A}"/> class.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="action">The action.</param>
        public SATupel(S state, A action)
            : base(state, action) {
        }

        #region Overrides

        /// <summary>
        /// Returns a <see cref="System.String" /> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String" /> that represents this instance.
        /// </returns>
        public override string ToString() {
            string str = "SATupel<" + typeof(S).Name + "," + typeof(A).Name + ">(";
            str += this.Item1.ToString() + "," + Item2.ToString() + ")";
            return str;
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object" /> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c>, wenn jeweils Item1 und Item2 gleich sind.</c>.
        /// </returns>
        public override bool Equals(object obj) {
            var other = obj as SATupel<S,A>;
            if (other == null)
                return false;
            return other.Item1.Equals(this.Item1) && other.Item2.Equals(this.Item2);
        }

        /// <summary>
        /// Returns a hash code for this instance. Basierend auf HashCode von Item1 und Item2.
        /// </summary>
        /// <returns>
        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
        /// </returns>
        public override int GetHashCode() {
            int hash = 13;
            hash = hash * 27 + Item1.GetHashCode();
            hash = hash * 11 + Item2.GetHashCode();
            return hash;
        }

        #endregion
    }
}
